/* src/common/interfaces/ecpg/compatlib/informix.cpp */

#define POSTGRES_ECPG_INTERNAL
#include "postgres_fe.h"

#include <math.h>
#include <ctype.h>
#include <limits.h>

#include <ecpgtype.h>
#include <ecpg_informix.h>
#include <pgtypes_error.h>
#include <pgtypes_date.h>
#include <pgtypes_numeric.h>
#include <sqltypes.h>
#include <sqlca.h>
#include <ecpgerrno.h>

/* this is also defined in ecpglib/misc.c, by defining it twice we don't have to export the symbol */

static struct sqlca_t sqlca_init = {{'S', 'Q', 'L', 'C', 'A', ' ', ' ', ' '},
    sizeof(struct sqlca_t),
    0,
    {0, {0}},
    {'N', 'O', 'T', ' ', 'S', 'E', 'T', ' '},
    {0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0},
    {'0', '0', '0', '0', '0'}};
static int deccall2(decimal* arg1, decimal* arg2, int (*ptr)(numeric*, numeric*))
{
    numeric *a1, *a2;
    int i;

    if ((a1 = PGTYPESnumeric_new()) == NULL)
        return ECPG_INFORMIX_OUT_OF_MEMORY;

    if ((a2 = PGTYPESnumeric_new()) == NULL) {
        PGTYPESnumeric_free(a1);
        return ECPG_INFORMIX_OUT_OF_MEMORY;
    }

    if (PGTYPESnumeric_from_decimal(arg1, a1) != 0) {
        PGTYPESnumeric_free(a1);
        PGTYPESnumeric_free(a2);
        return ECPG_INFORMIX_OUT_OF_MEMORY;
    }

    if (PGTYPESnumeric_from_decimal(arg2, a2) != 0) {
        PGTYPESnumeric_free(a1);
        PGTYPESnumeric_free(a2);
        return ECPG_INFORMIX_OUT_OF_MEMORY;
    }

    i = (*ptr)(a1, a2);

    PGTYPESnumeric_free(a1);
    PGTYPESnumeric_free(a2);

    return (i);
}

static int deccall3(decimal* arg1, decimal* arg2, decimal* result, int (*ptr)(numeric*, numeric*, numeric*))
{
    numeric *a1, *a2, *nres;
    int i;

    /*
     * we must NOT set the result to NULL here because it may be the same
     * variable as one of the arguments
     */
    if (risnull(CDECIMALTYPE, (char*)arg1) || risnull(CDECIMALTYPE, (char*)arg2))
        return 0;

    if ((a1 = PGTYPESnumeric_new()) == NULL)
        return ECPG_INFORMIX_OUT_OF_MEMORY;

    if ((a2 = PGTYPESnumeric_new()) == NULL) {
        PGTYPESnumeric_free(a1);
        return ECPG_INFORMIX_OUT_OF_MEMORY;
    }

    if ((nres = PGTYPESnumeric_new()) == NULL) {
        PGTYPESnumeric_free(a1);
        PGTYPESnumeric_free(a2);
        return ECPG_INFORMIX_OUT_OF_MEMORY;
    }

    if (PGTYPESnumeric_from_decimal(arg1, a1) != 0) {
        PGTYPESnumeric_free(a1);
        PGTYPESnumeric_free(a2);
        PGTYPESnumeric_free(nres);
        return ECPG_INFORMIX_OUT_OF_MEMORY;
    }

    if (PGTYPESnumeric_from_decimal(arg2, a2) != 0) {
        PGTYPESnumeric_free(a1);
        PGTYPESnumeric_free(a2);
        PGTYPESnumeric_free(nres);
        return ECPG_INFORMIX_OUT_OF_MEMORY;
    }

    i = (*ptr)(a1, a2, nres);

    if (i == 0) /* No error */
    {

        /* set the result to null in case it errors out later */
        rsetnull(CDECIMALTYPE, (char*)result);
        PGTYPESnumeric_to_decimal(nres, result);
    }

    PGTYPESnumeric_free(nres);
    PGTYPESnumeric_free(a1);
    PGTYPESnumeric_free(a2);

    return (i);
}

/* we start with the numeric functions */
int decadd(decimal* arg1, decimal* arg2, decimal* sum)
{
    errno = 0;
    int i = deccall3(arg1, arg2, sum, PGTYPESnumeric_add);

    if (i != 0) {
        if (errno == PGTYPES_NUM_OVERFLOW)
            return ECPG_INFORMIX_NUM_OVERFLOW;
        else if (errno == PGTYPES_NUM_UNDERFLOW)
            return ECPG_INFORMIX_NUM_UNDERFLOW;
        else if (errno != 0)
            return -1;
    }
    return 0;
}

int deccmp(decimal* arg1, decimal* arg2)
{
    return (deccall2(arg1, arg2, PGTYPESnumeric_cmp));
}

void deccopy(decimal* src, decimal* target)
{
    memcpy(target, src, sizeof(decimal));
}

static char* ecpg_strndup(const char* str, size_t len)
{
    size_t real_len = strlen(str);
    int use_len = (int)((real_len > len) ? len : real_len);

    char* newm = (char*)malloc(use_len + 1);

    if (newm != NULL) {
        memcpy(newm, str, use_len);
        newm[use_len] = '\0';
    } else
        errno = ENOMEM;

    return newm;
}

int deccvasc(char* cp, int len, decimal* np)
{
    char* str = NULL;
    int ret = 0;
    numeric* result = NULL;

    rsetnull(CDECIMALTYPE, (char*)np);
    if (risnull(CSTRINGTYPE, cp))
        return 0;

    str = ecpg_strndup(cp, len); /* decimal_in always converts the complete
                                  * string */
    if (str == NULL)
        ret = ECPG_INFORMIX_NUM_UNDERFLOW;
    else {
        errno = 0;
        result = PGTYPESnumeric_from_asc(str, NULL);
        if (result == NULL) {
            switch (errno) {
                case PGTYPES_NUM_OVERFLOW:
                    ret = ECPG_INFORMIX_NUM_OVERFLOW;
                    break;
                case PGTYPES_NUM_BAD_NUMERIC:
                    ret = ECPG_INFORMIX_BAD_NUMERIC;
                    break;
                default:
                    ret = ECPG_INFORMIX_BAD_EXPONENT;
                    break;
            }
        } else {
            int i = PGTYPESnumeric_to_decimal(result, np);

            PGTYPESnumeric_free(result);
            if (i != 0)
                ret = ECPG_INFORMIX_NUM_OVERFLOW;
        }
    }

    free(str);
    return ret;
}

int deccvdbl(double dbl, decimal* np)
{
    numeric* nres = NULL;
    int result = 1;

    rsetnull(CDECIMALTYPE, (char*)np);
    if (risnull(CDOUBLETYPE, (char*)&dbl))
        return 0;

    nres = PGTYPESnumeric_new();
    if (nres == NULL)
        return ECPG_INFORMIX_OUT_OF_MEMORY;

    result = PGTYPESnumeric_from_double(dbl, nres);
    if (result == 0)
        result = PGTYPESnumeric_to_decimal(nres, np);

    PGTYPESnumeric_free(nres);
    return (result);
}

int deccvint(int in, decimal* np)
{
    numeric* nres = NULL;
    int result = 1;

    rsetnull(CDECIMALTYPE, (char*)np);
    if (risnull(CINTTYPE, (char*)&in))
        return 0;

    nres = PGTYPESnumeric_new();
    if (nres == NULL)
        return ECPG_INFORMIX_OUT_OF_MEMORY;

    result = PGTYPESnumeric_from_int(in, nres);
    if (result == 0)
        result = PGTYPESnumeric_to_decimal(nres, np);

    PGTYPESnumeric_free(nres);
    return (result);
}

int deccvlong(long lng, decimal* np)
{
    numeric* nres = NULL;
    int result = 1;

    rsetnull(CDECIMALTYPE, (char*)np);
    if (risnull(CLONGTYPE, (char*)&lng))
        return 0;

    nres = PGTYPESnumeric_new();
    if (nres == NULL)
        return ECPG_INFORMIX_OUT_OF_MEMORY;

    result = PGTYPESnumeric_from_long(lng, nres);
    if (result == 0)
        result = PGTYPESnumeric_to_decimal(nres, np);

    PGTYPESnumeric_free(nres);
    return (result);
}

int decdiv(decimal* n1, decimal* n2, decimal* result)
{

    int i;

    errno = 0;
    i = deccall3(n1, n2, result, PGTYPESnumeric_div);

    if (i != 0)
        switch (errno) {
            case PGTYPES_NUM_DIVIDE_ZERO:
                return ECPG_INFORMIX_DIVIDE_ZERO;
                break;
            case PGTYPES_NUM_OVERFLOW:
                return ECPG_INFORMIX_NUM_OVERFLOW;
                break;
            default:
                return ECPG_INFORMIX_NUM_UNDERFLOW;
                break;
        }

    return 0;
}

int decmul(decimal* n1, decimal* n2, decimal* result)
{
    int i;

    errno = 0;
    i = deccall3(n1, n2, result, PGTYPESnumeric_mul);

    if (i != 0)
        switch (errno) {
            case PGTYPES_NUM_OVERFLOW:
                return ECPG_INFORMIX_NUM_OVERFLOW;
                break;
            default:
                return ECPG_INFORMIX_NUM_UNDERFLOW;
                break;
        }

    return 0;
}

int decsub(decimal* n1, decimal* n2, decimal* result)
{
    int i;

    errno = 0;
    i = deccall3(n1, n2, result, PGTYPESnumeric_sub);

    if (i != 0)
        switch (errno) {
            case PGTYPES_NUM_OVERFLOW:
                return ECPG_INFORMIX_NUM_OVERFLOW;
                break;
            default:
                return ECPG_INFORMIX_NUM_UNDERFLOW;
                break;
        }

    return 0;
}

int dectoasc(decimal* np, char* cp, int len, int right)
{
    char* str = NULL;
    numeric* nres = NULL;

    rsetnull(CSTRINGTYPE, (char*)cp);
    if (risnull(CDECIMALTYPE, (char*)np))
        return 0;

    nres = PGTYPESnumeric_new();
    if (nres == NULL)
        return ECPG_INFORMIX_OUT_OF_MEMORY;

    if (PGTYPESnumeric_from_decimal(np, nres) != 0) {
        PGTYPESnumeric_free(nres);
        return ECPG_INFORMIX_OUT_OF_MEMORY;
    }

    if (right >= 0)
        str = PGTYPESnumeric_to_asc(nres, right);
    else
        str = PGTYPESnumeric_to_asc(nres, nres->dscale);

    PGTYPESnumeric_free(nres);
    if (str == NULL)
        return -1;

    /*
     * TODO: have to take care of len here and create exponential notation if
     * necessary
     */
    if ((int)(strlen(str) + 1) > len) {
        if (len > 1) {
            cp[0] = '*';
            cp[1] = '\0';
        }
        free(str);
        return -1;
    } else {
        strcpy(cp, str);
        free(str);
        return 0;
    }
}

int dectodbl(decimal* np, double* dblp)
{
    int i;
    numeric* nres = PGTYPESnumeric_new();

    if (nres == NULL)
        return ECPG_INFORMIX_OUT_OF_MEMORY;

    if (PGTYPESnumeric_from_decimal(np, nres) != 0) {
        PGTYPESnumeric_free(nres);
        return ECPG_INFORMIX_OUT_OF_MEMORY;
    }

    i = PGTYPESnumeric_to_double(nres, dblp);
    PGTYPESnumeric_free(nres);

    return i;
}

int dectoint(decimal* np, int* ip)
{
    int ret;
    numeric* nres = PGTYPESnumeric_new();

    if (nres == NULL)
        return ECPG_INFORMIX_OUT_OF_MEMORY;

    if (PGTYPESnumeric_from_decimal(np, nres) != 0) {
        PGTYPESnumeric_free(nres);
        return ECPG_INFORMIX_OUT_OF_MEMORY;
    }

    ret = PGTYPESnumeric_to_int(nres, ip);
    PGTYPESnumeric_free(nres);

    if (errno == PGTYPES_NUM_OVERFLOW)
        ret = ECPG_INFORMIX_NUM_OVERFLOW;

    return ret;
}

int dectolong(decimal* np, long* lngp)
{
    int ret;
    numeric* nres = PGTYPESnumeric_new();

    if (nres == NULL)
        return ECPG_INFORMIX_OUT_OF_MEMORY;

    if (PGTYPESnumeric_from_decimal(np, nres) != 0) {
        PGTYPESnumeric_free(nres);
        return ECPG_INFORMIX_OUT_OF_MEMORY;
    }

    ret = PGTYPESnumeric_to_long(nres, lngp);
    PGTYPESnumeric_free(nres);

    if (errno == PGTYPES_NUM_OVERFLOW)
        ret = ECPG_INFORMIX_NUM_OVERFLOW;

    return ret;
}

/* Now the date functions */
int rdatestr(date d, char* str)
{
    char* tmp = PGTYPESdate_to_asc(d);

    if (tmp == NULL)
        return ECPG_INFORMIX_DATE_CONVERT;

    /* move to user allocated buffer */
    strcpy(str, tmp);
    free(tmp);

    return 0;
}

/*
 *
 * the input for this function is mmddyyyy and any non-numeric
 * character can be used as a separator
 *
 */
int rstrdate(char* str, date* d)
{
    return rdefmtdate(d, "mm/dd/yyyy", str);
}

void rtoday(date* d)
{
    PGTYPESdate_today(d);
    return;
}

int rjulmdy(date d, short mdy[3])
{
    int mdy_int[3];

    PGTYPESdate_julmdy(d, mdy_int);
    mdy[0] = (short)mdy_int[0];
    mdy[1] = (short)mdy_int[1];
    mdy[2] = (short)mdy_int[2];
    return 0;
}

int rdefmtdate(date* d, char* fmt, char* str)
{
    /* TODO: take care of DBCENTURY environment variable */
    /* PGSQL functions allow all centuries */

    errno = 0;
    if (PGTYPESdate_defmt_asc(d, fmt, str) == 0)
        return 0;

    switch (errno) {
        case PGTYPES_DATE_ERR_ENOSHORTDATE:
            return ECPG_INFORMIX_ENOSHORTDATE;
        case PGTYPES_DATE_ERR_EARGS:
        case PGTYPES_DATE_ERR_ENOTDMY:
            return ECPG_INFORMIX_ENOTDMY;
        case PGTYPES_DATE_BAD_DAY:
            return ECPG_INFORMIX_BAD_DAY;
        case PGTYPES_DATE_BAD_MONTH:
            return ECPG_INFORMIX_BAD_MONTH;
        default:
            return ECPG_INFORMIX_BAD_YEAR;
    }
}

int rfmtdate(date d, char* fmt, char* str)
{
    errno = 0;
    if (PGTYPESdate_fmt_asc(d, fmt, str) == 0)
        return 0;

    if (errno == ENOMEM)
        return ECPG_INFORMIX_OUT_OF_MEMORY;

    return ECPG_INFORMIX_DATE_CONVERT;
}

int rmdyjul(short mdy[3], date* d)
{
    int mdy_int[3];

    mdy_int[0] = mdy[0];
    mdy_int[1] = mdy[1];
    mdy_int[2] = mdy[2];
    PGTYPESdate_mdyjul(mdy_int, d);
    return 0;
}

int rdayofweek(date d)
{
    return (PGTYPESdate_dayofweek(d));
}

/* And the datetime stuff */

void dtcurrent(timestamp* ts)
{
    PGTYPEStimestamp_current(ts);
}

int dtcvasc(char* str, timestamp* ts)
{
    timestamp ts_tmp;
    int i;
    char** endptr = &str;

    errno = 0;
    ts_tmp = PGTYPEStimestamp_from_asc(str, endptr);
    i = errno;
    if (i)
        /* TODO: rewrite to Informix error codes */
        return i;
    if (**endptr) {
        /* extra characters exist at the end */
        return ECPG_INFORMIX_EXTRA_CHARS;
    }
    /* TODO: other Informix error codes missing */

    /* everything went fine */
    *ts = ts_tmp;

    return 0;
}

int dtcvfmtasc(char* inbuf, char* fmtstr, timestamp* dtvalue)
{
    return PGTYPEStimestamp_defmt_asc(inbuf, fmtstr, dtvalue);
}

int dtsub(timestamp* ts1, timestamp* ts2, interval* iv)
{
    return PGTYPEStimestamp_sub(ts1, ts2, iv);
}

int dttoasc(timestamp* ts, char* output)
{
    char* asctime = PGTYPEStimestamp_to_asc(*ts);

    strcpy(output, asctime);
    free(asctime);
    return 0;
}

int dttofmtasc(timestamp* ts, char* output, int str_len, char* fmtstr)
{
    return PGTYPEStimestamp_fmt_asc(ts, output, str_len, fmtstr);
}

int intoasc(interval* i, char* str)
{
    errno = 0;
    str = PGTYPESinterval_to_asc(i);

    if (str == NULL)
        return -errno;

    return 0;
}

/*
 *	rfmt.c	-  description
 *	by Carsten Wolff <carsten.wolff@credativ.de>, Wed Apr 2 2003
 */

static struct {
    long val;
    int maxdigits;
    int digits;
    int remaining;
    char sign;
    char* val_string;
} value;

/**
 * initialize the struct, which holds the different forms
 * of the long value
 */
static int initValue(long lng_val)
{
    int i, j;
    long l, dig;

    /* set some obvious things */
    value.val = lng_val >= 0 ? lng_val : lng_val * (-1);
    value.sign = lng_val >= 0 ? '+' : '-';
    value.maxdigits = log10(2) * (8 * sizeof(long) - 1);

    /* determine the number of digits */
    i = 0;
    l = 1;
    do {
        i++;
        l *= 10;
    } while ((l - 1) < value.val && l <= LONG_MAX / 10);

    if (l <= LONG_MAX / 10) {
        value.digits = i;
        l /= 10;
    } else
        value.digits = i + 1;

    value.remaining = value.digits;

    /* convert the long to string */
    if ((value.val_string = (char*)malloc(value.digits + 1)) == NULL)
        return -1;
    dig = value.val;
    for (i = value.digits, j = 0; i > 0; i--, j++) {
        value.val_string[j] = dig / l + '0';
        dig = dig % l;
        l /= 10;
    }
    value.val_string[value.digits] = '\0';
    return 0;
}

/* return the position oft the right-most dot in some string */
static int getRightMostDot(char* str)
{
    size_t len = strlen(str);
    int i, j;

    j = 0;
    for (i = len - 1; i >= 0; i--) {
        if (str[i] == '.')
            return len - j - 1;
        j++;
    }
    return -1;
}

/* And finally some misc functions */
int rfmtlong(long lng_val, char* fmt, char* outbuf)
{
    size_t fmt_len = strlen(fmt);
    size_t temp_len;
    int i, j, /* position in temp */
        k, dotpos;
    int leftalign = 0, blank = 0, sign = 0, entitydone = 0, signdone = 0, brackets_ok = 0;
    char* temp = NULL;
    char tmp[2] = " ";
    char lastfmt = ' ', fmtchar = ' ';

    temp = (char*)malloc(fmt_len + 1);
    if (temp == NULL) {
        errno = ENOMEM;
        return -1;
    }

    /* put all info about the long in a struct */
    if (initValue(lng_val) == -1) {
        free(temp);
        errno = ENOMEM;
        return -1;
    }

    /* '<' is the only format, where we have to align left */
    if (strchr(fmt, (int)'<') != NULL)
        leftalign = 1;

    /* '(' requires ')' */
    if ((strchr(fmt, (int)'(') != NULL) && (strchr(fmt, (int)')') != NULL))
        brackets_ok = 1;

    /* get position of the right-most dot in the format-string */
    /* and fill the temp-string wit '0's up to there. */
    dotpos = getRightMostDot(fmt);

    /* start to parse the formatstring */
    temp[0] = '\0';
    k = value.digits - 1; /* position in the value_string */
    for (i = fmt_len - 1, j = 0; i >= 0; i--, j++) {
        /* qualify, where we are in the value_string */
        if (k < 0) {
            blank = 1;
            if (k == -1)
                sign = 1;
            if (leftalign) {
                /* can't use strncat(,,0) here, Solaris would freek out */
                if (sign)
                    if (signdone) {
                        temp[j] = '\0';
                        break;
                    }
            }
        }
        /* if we're right side of the right-most dot, print '0' */
        if (dotpos >= 0 && dotpos <= i) {
            if (dotpos < i) {
                if (fmt[i] == ')')
                    tmp[0] = value.sign == '-' ? ')' : ' ';
                else
                    tmp[0] = '0';
            } else
                tmp[0] = '.';
            strcat(temp, tmp);
            continue;
        }
        /* the ',' needs special attention, if it is in the blank area */
        if (blank && fmt[i] == ',')
            fmtchar = lastfmt;
        else
            fmtchar = fmt[i];
        /* waiting for the sign */
        if (k < 0 && leftalign && sign && !signdone && fmtchar != '+' && fmtchar != '-')
            continue;
        /* analyse this format-char */
        switch (fmtchar) {
            case ',':
                tmp[0] = ',';
                k++;
                break;
            case '*':
                if (blank)
                    tmp[0] = '*';
                else
                    tmp[0] = value.val_string[k];
                break;
            case '&':
                if (blank)
                    tmp[0] = '0';
                else
                    tmp[0] = value.val_string[k];
                break;
            case '#':
                if (blank)
                    tmp[0] = ' ';
                else
                    tmp[0] = value.val_string[k];
                break;
            case '-':
                if (sign && value.sign == '-' && !signdone) {
                    tmp[0] = '-';
                    signdone = 1;
                } else if (blank)
                    tmp[0] = ' ';
                else
                    tmp[0] = value.val_string[k];
                break;
            case '+':
                if (sign && !signdone) {
                    tmp[0] = value.sign;
                    signdone = 1;
                } else if (blank)
                    tmp[0] = ' ';
                else
                    tmp[0] = value.val_string[k];
                break;
            case '(':
                if (sign && brackets_ok && value.sign == '-')
                    tmp[0] = '(';
                else if (blank)
                    tmp[0] = ' ';
                else
                    tmp[0] = value.val_string[k];
                break;
            case ')':
                if (brackets_ok && value.sign == '-')
                    tmp[0] = ')';
                else
                    tmp[0] = ' ';
                break;
            case '$':
                if (blank && !entitydone) {
                    tmp[0] = '$';
                    entitydone = 1;
                } else if (blank)
                    tmp[0] = ' ';
                else
                    tmp[0] = value.val_string[k];
                break;
            case '<':
                tmp[0] = value.val_string[k];
                break;
            default:
                tmp[0] = fmt[i];
        }
        strcat(temp, tmp);
        lastfmt = fmt[i];
        k--;
    }
    /* safety-net */
    temp[fmt_len] = '\0';

    /* reverse the temp-string and put it into the outbuf */
    temp_len = strlen(temp);
    outbuf[0] = '\0';
    for (i = temp_len - 1; i >= 0; i--) {
        tmp[0] = temp[i];
        strcat(outbuf, tmp);
    }
    outbuf[temp_len] = '\0';

    /* cleaning up */
    free(temp);
    free(value.val_string);

    return 0;
}

void rupshift(char* str)
{
    for (; *str != '\0'; str++)
        if (islower((unsigned char)*str))
            *str = toupper((unsigned char)*str);
    return;
}

int byleng(char* str, int len)
{
    for (len--; str[len] && str[len] == ' '; len--)
        ;
    return (len + 1);
}

void ldchar(char* src, int len, char* dest)
{
    int dlen = byleng(src, len);

    memmove(dest, src, dlen);
    dest[dlen] = '\0';
}

int rgetmsg(int msgnum, char* s, int maxsize)
{
    (void)msgnum;  /* keep the compiler quiet */
    (void)s;       /* keep the compiler quiet */
    (void)maxsize; /* keep the compiler quiet */
    return 0;
}

int rtypalign(int offset, int type)
{
    (void)offset; /* keep the compiler quiet */
    (void)type;   /* keep the compiler quiet */
    return 0;
}

int rtypmsize(int type, int len)
{
    (void)type; /* keep the compiler quiet */
    (void)len;  /* keep the compiler quiet */
    return 0;
}

int rtypwidth(int sqltype, int sqllen)
{
    (void)sqltype; /* keep the compiler quiet */
    (void)sqllen;  /* keep the compiler quiet */
    return 0;
}

void ECPG_informix_set_var(int number, void* pointer, int lineno)
{
    ECPGset_var(number, pointer, lineno);
}

void* ECPG_informix_get_var(int number)
{
    return ECPGget_var(number);
}

void ECPG_informix_reset_sqlca(void)
{
    struct sqlca_t* sqlca = ECPGget_sqlca();

    memcpy((char*)sqlca, (char*)&sqlca_init, sizeof(struct sqlca_t));
}

int rsetnull(int t, char* ptr)
{
    ECPGset_noind_null((ECPGttype)t, ptr);
    return 0;
}

int risnull(int t, char* ptr)
{
    return (ECPGis_noind_null((ECPGttype)t, ptr));
}
